#Python 3.9.2(1620514485-刘阳阳-BJ-EICCIE)
import time
from ncclient import manager
import xml
import xmlrpc
import xml.etree.ElementTree as ET
import paramiko
import ipaddress
from prettytable import PrettyTable
#配置思科环回口地址XML
CONFIG_CISCO_LOOP="""
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
      <native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native">
        <interface>
          <Loopback>
            <name>0</name>
            <description>configed by netconf</description>
            <ip>
              <address>
                <primary xc:operation="merge">
                  <address>22.22.22.22</address>
                  <mask>255.255.255.255</mask>
                </primary>
              </address>
            </ip>
          </Loopback>
        </interface>
      </native>
</config>
"""
#配置思科OSPFXML
CONFIG_CISCO_OSPF="""
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
 <native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native">
        <router>
          <router-ospf xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-ospf">
            <ospf>
              <process-id xc:operation="merge">
                <id>1</id>
                <router-id>22.22.22.22</router-id>
              </process-id>
            </ospf>
          </router-ospf>
        </router>
        <interface>
          <GigabitEthernet>
            <name>1</name>
            <description>configed by netconf</description>
            <ip>
              <router-ospf xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-ospf">
                <ospf>
                  <process-id>
                    <id>1</id>
                    <area>
                      <area-id>0</area-id>
                    </area>
                  </process-id>
                  <cost>10</cost>
                  <network>
                    <broadcast/>
                  </network>
                  <priority>255</priority>
                </ospf>
              </router-ospf>
            </ip>
          </GigabitEthernet>
          <Loopback>
            <name>0</name>
            <ip>
              <router-ospf xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-ospf">
                <ospf>
                  <process-id>
                    <id>1</id>
                    <area>
                      <area-id>0</area-id>
                    </area>
                  </process-id>
                  <network>
                    <point-to-point/>
                  </network>
                </ospf>
              </router-ospf>
            </ip>
          </Loopback>
        </interface>
 </native>
</config>
"""
#获取思科OSPF邻居状态信息XML
GET_CISCO_OSPF_NBR="""
    <filter>
      <ospf-oper-data xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-ospf-oper">
        <ospf-state>
          <ospf-instance>
            <ospf-area>
              <ospf-interface>
                <ospf-neighbor/>
              </ospf-interface>
            </ospf-area>
          </ospf-instance>
        </ospf-state>
      </ospf-oper-data>
    </filter>
"""
#配置华为环回口地址XML
CONFIG_HUAWEI_LOOP="""
<config>
 <ifm content-version="1.0" format-version="1.0" xmlns="http://www.huawei.com/netconf/vrp">
  <interfaces>
   <interface>
     <ifName>loopback0</ifName>
     <ifmAm4>
      <am4CfgAddrs>
        <am4CfgAddr operation="remove">   <!-- CE要求必须先删除main地址，而且必须填写正确原来的地址信息 -->
         <addrType>main</addrType>
         <ifIpAddr>22.22.22.22</ifIpAddr>
        </am4CfgAddr>
        <am4CfgAddr operation="merge">
         <ifIpAddr>11.11.11.11</ifIpAddr>
         <subnetMask>255.255.255.255</subnetMask>
         <addrType>main</addrType>
        </am4CfgAddr>
      </am4CfgAddrs>
     </ifmAm4>
   </interface>
  </interfaces>
 </ifm>
</config>
"""
#配置华为OSPFXML
CONFIG_HUAWEI_OSPF= """
<config>
      <ospfv2 xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0">
        <ospfv2comm>
          <ospfSites>
            <ospfSite>
              <processId>1</processId>
              <areas>
                <area>
                  <areaId>0.0.0.0</areaId>
                  <interfaces>
                    <interface operation="merge">
                      <ifName>GE1/0/0</ifName>
                      <configCost>10</configCost>
                      <networkType>broadcast</networkType>
                    </interface>
                    <interface operation="merge">
                      <ifName>LoopBack0</ifName>
                      <networkType>p2p</networkType>
                    </interface>
                  </interfaces>
                </area>
              </areas>
            </ospfSite>
          </ospfSites>
        </ospfv2comm>
      </ospfv2>
</config>
"""
#获取华为OSPF邻居状态信息XML
GET_HUAWEI_OSPF_NBR="""
<filter type="subtree">
      <ospfv2 xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0">
        <ospfv2comm>
          <ospfSites>
            <ospfSite>
              <neighbors>
                <neighbor>
                </neighbor>
              </neighbors>
            </ospfSite>
          </ospfSites>
        </ospfv2comm>
      </ospfv2>
</filter>
"""
# 配置CISCO和HUAWEI接口、OSPF
def configuration(plat,m):
    if plat == 'csr':
        config_al=[CONFIG_CISCO_OSPF,CONFIG_CISCO_LOOP]
    if plat=='huawei':
        config_al=[CONFIG_HUAWEI_LOOP,CONFIG_HUAWEI_OSPF]
    for configfinal in config_al:
        m.edit_config(target='running',config=configfinal)
#获取CISCO和HUAWEI状态信息
def OSPF_STATE(plat, m):
    if plat == 'csr':
        #通过NETCONF获取OSPF邻居状态信息
        status=m.get(GET_CISCO_OSPF_NBR)
        # 将xml编码的数据解读为 'lxml.etree._Element'
        status1=status.data
        #标签路径
        routerid='{http://cisco.com/ns/yang/Cisco-IOS-XE-ospf-oper}neighbor-id'
        #lxml中findtext依据标签路径查找数据亦或者标签名也可以
        routerid_value=status1.findtext(".//"+routerid)
        #ipaddress库换算10进制IP数值为点分10进制
        if routerid_value.find('.')==-1 :
            nbrid=ipaddress.ip_address(int(routerid_value))
        else:
            nbrid=routerid_value
        nbrip='{http://cisco.com/ns/yang/Cisco-IOS-XE-ospf-oper}address'
        nbrip_value=status1.findtext(".//"+nbrip)
        ospfdr='{http://cisco.com/ns/yang/Cisco-IOS-XE-ospf-oper}dr'
        ospfdr_value=status1.findtext(".//"+ospfdr)
        ospfstate='{http://cisco.com/ns/yang/Cisco-IOS-XE-ospf-oper}state'
        ospfstate_text = status1.findtext(".//" + ospfstate).split('-')[-1].upper()
    if plat=='huawei':
        status=m.get(GET_HUAWEI_OSPF_NBR)
        # 将xml编码的数据解读为 'lxml.etree._Element'
        status1=status.data
        routerid='{http://www.huawei.com/netconf/vrp}nbrRouterId'
        routerid_value=status1.findtext(".//"+routerid)
        if routerid_value.find('.')==-1 :
            nbrid=ipaddress.ip_address(int(routerid_value))
        else:
            nbrid=routerid_value
        nbrip = '{http://www.huawei.com/netconf/vrp}nbrIpAddr'
        nbrip_value = status1.findtext(".//" + nbrip)
        ospfdr='{http://www.huawei.com/netconf/vrp}nbrDR'
        ospfdr_value=status1.findtext(".//"+ospfdr)
        ospfstate='{http://www.huawei.com/netconf/vrp}nbrState'
        ospfstate_text = status1.findtext(".//" + ospfstate).upper()
    return nbrid, nbrip_value, ospfdr_value, ospfstate_text
if __name__=='__main__':
    configfinal = ''
    config_al = []
    device_lists = [{'name': 'csr', 'host': '203.0.113.2', 'username': 'qytang', 'password': '123qwe!@#QWE'},
                    {'name': 'huawei', 'host': '203.0.113.1', 'username': 'qytang', 'password': '123qwe!@#QWE'}]
    tb = PrettyTable()
    #设置表格各列的名字
    tb.field_names = ["NO", "Plat", "Nbr_ID", "Nbr_IP", "Ospfdr_IP", "Ospfstate"]
    for i in range(len(device_lists)):
        plat=device_lists[i]['name']
        hostip=device_lists[i]['host']
        uname=device_lists[i]['username']
        pwd=device_lists[i]['password']
        m=manager.connect(host=hostip, port=830,
                                    username=uname,
                                    password=pwd,
                                    hostkey_verify=False,
                                    device_params={'name':plat},
                                    allow_agent=False,
                                    look_for_keys=False)
        #调用配置模块
        configuration(plat,m)
        #调用获取状态信息模块，并取得返回值
        nbr_id,nbr_ip,ospfdr_ip,ospfstate=OSPF_STATE(plat,m)
        #按行将数据放入表格
        tb.add_row([i,plat,nbr_id,nbr_ip,ospfdr_ip,ospfstate])
    print(tb)
    #获取本地时间
    nowtime=time.strftime('%Y_%m_%d_%H_%M',time.localtime(time.time()))
    with open("OSPFstate{}.txt".format(nowtime),"w+") as f:
        f.write(str(tb))